home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
-
- ilbm.c -- routines to read IFF.ILBM files written by Ray Lambert
- These routines are public domain
-
- ****************************************************************************/
-
- #include <stdio.h>
- #include "keeper.h"
- #include <exec/memory.h>
- #include <hardware/blit.h>
- #include <hardware/custom.h>
- #include <proto/dos.h>
- #include <proto/exec.h>
- #include <proto/graphics.h>
-
-
- /*
- ** IFF.ILBM stuff...
- */
- struct BitMapHeader
- {
- UWORD w,h;
- WORD x,y;
- UBYTE nPlanes;
- UBYTE masking;
- UBYTE compression;
- UBYTE pad1;
- UWORD transparentColor;
- UBYTE xAspect,yAspect;
- WORD pageWidth,pageHeight;
- };
-
- /*
- ** compression types
- */
- #define cmpNone 0
- #define cmpByteRun1 1
-
- /*
- ** info to identify a mask
- */
- #define mskNone 0
- #define mskHasMask 1
- #define mskHasTransparentColor 2
- #define mskLasso 3
-
- /*
- ** IFF.ILBM chunk names
- */
- #define MakeID(a,b,c,d) ((a)<<24|(b)<<16|(c)<<8|(d))
- #define FORM MakeID('F','O','R','M')
- #define ILBM MakeID('I','L','B','M')
- #define BMHD MakeID('B','M','H','D')
- #define CMAP MakeID('C','M','A','P')
- #define CAMG MakeID('C','A','M','G')
- #define BODY MakeID('B','O','D','Y')
-
-
-
- /*
- ** Copy from 'src' to 'dst' -- 'dst' must receive 'rowlen' bytes --
- ** bytes at 'src' may be compressed -- 'comp' indicates if compression
- ** was used and if so what type -- returns the number of bytes read
- ** from 'src' -- 'src' may be 0 and if so 'rowlen' zero bytes are placed
- ** in 'dest' regardless of 'comp' -- 'dst' may be 0 and if so no bytes
- ** are actually stored but 'src' is treated normally, allowing the caller
- ** to determine how many 'src' bytes to skip in case 'src' is compressed
- */
- static ULONG copy_line(UBYTE *src, UBYTE *dst, UBYTE comp, ULONG rowlen)
- {
- register ULONG cnt;
- register signed char b;
-
- /*
- ** no source data - fill "dst" with "rowlen" zero bytes
- */
- unless( src )
- {
- memset(dst,0,rowlen);
- return(0);
- }
-
- /*
- ** no compression used - just do a direct copy
- */
- if (comp == cmpNone)
- {
- if (dst) memcpy(dst,src,rowlen);
- return(rowlen);
- }
-
- /*
- ** data is compressed -- expand "rowlen" number of bytes
- ** "cnt" counts the number of bytes read from "src"
- ** "rowlen" counts-down the number of bytes to put into "dst"
- */
- cnt = 0;
- while(rowlen > 0)
- {
- b = *src;
- src++;
- cnt++;
- if (b == -128) continue;
-
- if (b >= 0)
- {
-
- /*
- ** copy "b" + 1 bytes directly
- */
- b++;
- if (rowlen < b) b = rowlen;
- rowlen -= b;
- if (dst)
- {
- memcpy(dst,src,b);
- dst += b;
- }
- src += b;
- cnt += b;
- }
- else
- {
-
- /*
- ** replicate byte at "src" (abs(b) + 1) times
- */
- b = ( abs(b) + 1 );
- if (b > rowlen) b = rowlen;
- rowlen -= b;
- if (dst)
- {
- memset(dst,*src,b);
- dst += b;
- }
- src++;
- cnt++;
- }
-
- }
-
- return(cnt);
- }
-
-
-
- /*
- ** Load the BODY data from an ILBM file
- */
- static BOOL loadBODY(BPTR file, ULONG len, struct BitMapHeader *bmhd,
- struct BLITmap *bm)
- {
- ULONG
- rowlen,
- cnt,
- pcnt;
- PLANEPTR
- body,
- b,
- p[8];
-
- /*
- ** calculate number of bytes in one row
- */
- rowlen = ( ( (bmhd->w + 15) / 16 ) * 2 );
-
- /*
- ** allocate memory for each plane
- */
- for(pcnt = 0; pcnt < bmhd->nPlanes; pcnt++)
- unless( bm->p[pcnt] = p[pcnt] = AllocRaster(bmhd->w,bmhd->h) )
- return(FALSE);
-
- /*
- ** allocate memory to load body chunk into
- */
- unless( b = body = AllocMem(len,0) ) return(FALSE);
-
- /*
- ** read the BODY chunk into memory
- */
- unless( Read(file,body,len) == len )
- {
- FreeMem(body,len);
- return(FALSE);
- }
-
- /*
- ** expand interleaved BODY chunk into seperate planes
- */
- for(cnt = 0; cnt < bmhd->h; cnt++)
- {
-
- /*
- ** use "copy_line()" to expand a single line into each plane
- */
- for(pcnt = 0; pcnt < bmhd->nPlanes; pcnt++)
- {
- b += copy_line(b, p[pcnt], bmhd->compression, rowlen);
- p[pcnt] += rowlen;
- }
-
- /*
- ** skip the mask data line (if there is any)
- */
- if (bmhd->masking == mskHasMask)
- {
- b += copy_line(b, 0, bmhd->compression, rowlen);
- }
-
- }
-
- /*
- ** free the temporary buffer used for the BODY chunk
- */
- FreeMem(body,len);
-
- /*
- ** all's well that ends well
- */
- return(TRUE);
- }
-
-
-
- /*
- ** load a CMAP chunk and pack it into an Amiga color map (palette)
- */
- static BOOL loadCMAP(BPTR file, ULONG len, UWORD *cmap)
- {
- UBYTE rgb[3*32]; /* buffer to read raw RGB bytes from file */
- ULONG cnt;
-
- cnt = min(len,sizeof(rgb)); /* don't load more than 'rgb' can hold */
- unless( Read(file,rgb,cnt) == cnt ) return(FALSE);
- if (len > cnt) Seek(file,(len-cnt),OFFSET_CURRENT); /* skip unused bytes */
- cnt /= 3; /* number of colors for CMAP (triplets of bytes in 'rgb') */
- PackCMAP(rgb,cmap,cnt);
- return(TRUE);
- }
-
-
-
- /*
- ** load an IFF.ILBM picture from disk
- */
- struct BLITmap *loadILBM(char *name)
- {
- BPTR file;
- ULONG type, len;
- struct BitMapHeader bmhd;
- struct BLITmap *bm;
-
- unless( bm = (struct BLITmap *)AllocMem(sizeof(struct BLITmap),MEMF_CLEAR) )
- return(0);
- unless( file = Open(name,MODE_OLDFILE) )
- {
- FreeMem(bm,sizeof(struct BLITmap));
- return(0);
- }
-
- unless( (Read(file,(UBYTE *)&type,4) == 4) && (type == FORM) )
- {
- enderr:
- Close(file);
- if (bm) unloadILBM(bm);
- return(0);
- }
- unless( Read(file,(UBYTE *)&len,4) == 4 ) goto enderr; /* FORM length */
- unless( (Read(file,(UBYTE *)&type,4) == 4) && (type == ILBM) ) goto enderr;
-
- memset(bm->cmap,0,sizeof(bm->cmap)); /* clear the CMAP in case none in file */
- bm->modes = 0; /* clear the modes in case none in file */
- bmhd.w = 0; /* flag if a BMHD chunk has been found */
-
- until(6==9)
- {
- unless( Read(file,(UBYTE *)&type,4) == 4) goto enderr; /* chunk type */
- unless( Read(file,(UBYTE *)&len,4) == 4) goto enderr; /* chunk length */
-
- switch(type)
- {
- case BMHD:
- {
- unless( len == sizeof(struct BitMapHeader) ) goto enderr;
- unless( Read(file,(UBYTE *)&bmhd,len) == len ) goto enderr;
- bm->w = bmhd.w;
- bm->h = bmhd.h;
- bm->d = bmhd.nPlanes;
- bm->wpl = ( (bmhd.w + 15) / 16 );
- break;
- }
- case CMAP:
- {
- unless( loadCMAP(file,len,bm->cmap) ) goto enderr;
- break;
- }
- case CAMG:
- {
- unless( Read(file,(UBYTE *)&bm->modes,4) == 4 ) goto enderr;
- if (len > 4) Seek(file,(len-4),OFFSET_CURRENT);
- break;
- }
- case BODY:
- {
- goto doBODY;
- }
- default: /* skip unused chunk */
- {
- Seek(file,len,OFFSET_CURRENT);
- break;
- }
- }
-
- if (len & 1) Seek(file,1,OFFSET_CURRENT); /* odd sized chunk? */
- }
-
- doBODY:
- unless( bmhd.w > 0 ) goto enderr; /* no BMHD found? */
- unless( (bmhd.compression == cmpNone) /* cmpression we don't support? */
- || (bmhd.compression == cmpByteRun1) ) goto enderr;
- unless( loadBODY(file,len,&bmhd,bm) ) goto enderr;
-
- Close(file);
-
- return(bm);
- }
-
-
-
- /*
- ** Free all memory associated with a BLITmap, including all bitplanes,
- ** the mask plane and the BLITmap structure itself.
- */
- void unloadILBM(struct BLITmap *bm)
- {
- register int i;
- if (bm)
- {
- for(i = 0; i < bm->d; i++)
- {
- if (bm->p[i]) FreeRaster(bm->p[i],bm->w,bm->h);
- }
- if (bm->m) FreeRaster(bm->m,bm->w,bm->h);
- FreeMem(bm,sizeof(struct BLITmap));
- }
- }
-
-
-
- /*
- ** initialize a BitMap structure with info from a BLITmap structure
- */
- void BLITmap2BitMap(struct BLITmap *a, struct BitMap *b)
- {
- register int i;
- InitBitMap(b,a->d,a->w,a->h);
- for(i = 0; i < a->d; i++) b->Planes[i] = a->p[i];
- }
-